//////////////////////////////////////////////////////////////////////////////////////////////////////
// 项目名   : Container
// 文件名   : Vector.h
// 作者     : Aiye
// 日期     : 2025/8/31 22:10
// 邮箱     : 2878548868@qq.com
// 摘要     : 介绍vector容器
//////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef CONTAINER_VECTOR_H
#define CONTAINER_VECTOR_H
#include <string>
#include <vector>
#include "GlobalVariable.h"

class TestVector
{
public:
    /**
     * @brief 介绍构造函数
     */
    static void TestConstuctor()
    {
        std::vector<int> nVec1(); // 默认构造函数，构造一个整形的容器
        std::vector<int> nVec2(3); // 构造一个包含3个元素的容器
        std::vector<int> nVec3(3,3); // 构造一个三个元素的值都为3的元素
        auto nVec4{nVec3}; // 拷贝构造
        auto nVec5{std::move(nVec4)}; // 移动构造函数
        std::vector<int> nVec6{1,2,3,4}; // 初始化列表构造，推荐使用
        decltype(nVec6)().swap(nVec6); // 析构释放。
    }

    /**
     * @brief 介绍赋值
     */
    static void TestAssign()
    {
        std::vector<std::string> strVec1{"Hello String" ,"Hello Vector" , "Hello Map"}; // 创建一个
        auto strVec2 = strVec1; // 赋值拷贝
        auto strVec3 = std::move(strVec2); // 移动赋值拷贝
        std::vector<std::string> strVec4{};
        strVec4.assign(strVec1.begin() , strVec1.end());
        strVec4.assign(3,"Hello");
    }

    /**
     * @brief 介绍容量
     */
    static void TestCapacity()
    {
        // 编译器在知道事先需要多少内存的情况下会进行精准的内存分配
        std::vector<int> nVec{1,2,3,4,5,6}; // 构造一个空的容器
        std::cout << "The vector's capacity:" << nVec.capacity() << std::endl;
        std::cout << "The vector's size:" << nVec.size() << std::endl;  // 在初始化列表中 size == capacity

        nVec.push_back(7); // 往后加入一个数值
        std::cout << "The vector's capacity:" << nVec.capacity() << std::endl; // capacity  1 -> 2 -> 4 -> 8 等倍数扩大
        std::cout << "The vector's size:" << nVec.size() << std::endl;

        std::cout << "Container is ： " << nVec.empty(); // 判断容器是否为空
        nVec.shrink_to_fit(); // 缩放容器大小，不推荐使用，实际上通过构建合适大小的内存块进行转移操作。

        // 为了防止内存多次扩容等情况一般需要在初始化的时候就分配内存大小
        std::vector<int> nVec2{0,10};
        nVec2.reserve(10); // 扩容
    }

    /**
     * @brief 介绍vector的增删查改
     */
    static void TestCRUD()
    {
        { // 介绍增加操作
            std::vector<int> nVec{1, 2, 3};
            nVec.reserve(10);

            // 右值通过移动构造，左值则通过拷贝构造
            nVec.push_back(4); // 向尾部添加一个数，不需要进行数据移动

            std::vector<Person> perVec{{"Aice", 18}};
            perVec.push_back(Person("Aiye", 22)); // 构架一个临时对象再移动

            // 在容器尾部就地构造一个元素，避免临时对象的创建和拷贝/移动操作。性能通常优于 push_back。
            perVec.emplace_back(Person("Joker", 21));

            auto it = nVec.begin();
            nVec.insert(it + 1, 0); // 在第二个位置插入
            nVec.insert(nVec.end(), 3, 20); // 在末尾插入3个数
            nVec.emplace(it, 1); // 类似于emplace_back,在固定位置构造
        }

        { // 介绍删除操作
            std::vector<int> nVec{1,2,3,4,5};
            nVec.pop_back(); // 尾部删除最高效
            auto it = nVec.begin();
            nVec.erase(it+1); // 删除第二个数

            // 进行第一次删除操作后迭代器已经变换
            it = nVec.begin();
            nVec.erase(it , it +1); // 删除第一个数和第二个数之间的所有数
            nVec.clear(); // 清除所有元素
        }

        {// 介绍查操作
            std::vector<int> nVec{1,2,3,4,5,5,6,6};
            // [] 下标访问
            std::cout << "The second element is : " << nVec[1] << std::endl;
            // nVec[20]; 越界访问，下标运算没有边界检查，
            // 有些容器是写时赋值的利用下标访问会触发写的操作所以不推荐下标访问。

            for (int i = 0; i < nVec.size(); ++i)
            {
                std::cout << "The element i" << nVec.at(i) << std::endl;
            }

            std::cout << "The first element is:" << nVec.front() << std::endl;
            std::cout << "The last element is:" << nVec.back() << std::endl;
        }

        { // 介绍修改的操作
            std::vector<int> nVec{1,2,3,4,5,6,7,8};
            nVec[0] = 0; // 下标直接修改
            nVec.at(1) = 1; // 更安全
            auto pNum = nVec.data(); // 直接获取指针数组进行更改
            pNum[2] = 2; // 一般不推荐

            // 迭代器遍历修改
            auto it = nVec.begin(); // 正向迭代器
            *(it+3) = 3; //
            auto rit = nVec.rbegin(); // 获取反向迭代器
            *rit = 7 ; // 修改最后一个数据

            for (int& vec : nVec)
            {
                // 范围for引用修改
                if (vec > 3 && vec < 8)
                {
                    vec--;
                }
            }
        }
    }
};
#endif //CONTAINER_VECTOR_H